/******************************************************************************
 *  _____     _____
 *  \  __\    \  __\
 *   \ \_\\    \ \_\\
 *    \  __\SS  \  __\roject
 *     \_\       \_\
 *
 * Mateusz Maciąg, Rafał Urbański
 * Komputerowe Systemy Sterowania
 *****************************************************************************/

#include "MainWindow.h"
#include "ui_MainWindow.h"

#include "OscilloscopeData.h"
#include "SimInterface/SimulatorManager.h"
#include "SimFile/ConfigReader.h"
#include <string>
#include <sstream>

#include <QFileDialog>
#include <QMessageBox>
#include <QPixmap>
#include <QClipboard>

#include <vector>
#include <auto_ptr.h>

using namespace RafMat::UI;
using namespace RafMat::SimInterface;

const unsigned MainWindow::DEFAULT_PLOT_BUFFER_SIZE = 1000;
const QwtPlotCurve::CurveStyle MainWindow::DEFAULT_STYLE = QwtPlotCurve::Lines;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_simulator(SimulatorManager::getSimulator())
{
    ui->setupUi(this);

    initializePlots();
    initializeTimer();

    connect(ui->actionSave_as, SIGNAL(triggered()), this, SLOT(on_actionSaveAs_triggered()));
    connect(ui->actionSave, SIGNAL(triggered()), this, SLOT(on_actionSave_triggered()));
    connect(ui->actionOpen_simulation, SIGNAL(triggered()), this, SLOT(on_actionOpen_triggered()));
    connect(ui->actionCopy_Clp, SIGNAL(triggered()), this, SLOT(copyPlotToClipboard()));

    m_neverSaved = true;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initializeTimer()
{
    m_timer = new QTimer(this);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(on_timer()));
    m_timer->setInterval(200);
}

void MainWindow::initializePlots()
{
    m_simSettings = new SimulatorSettings(this);
    m_simSettings->attachSimulator(m_simulator);

    m_inputWaveform = new OscilloscopeData(DEFAULT_PLOT_BUFFER_SIZE);
    m_outputWaveform = new OscilloscopeData(DEFAULT_PLOT_BUFFER_SIZE);
    m_controlWaveform = new OscilloscopeData(DEFAULT_PLOT_BUFFER_SIZE);

    m_curveInput = new QwtPlotCurve("Input");
    m_curveOutput = new QwtPlotCurve("Output");
    m_curveControl = new QwtPlotCurve("Control");

    m_curveInput->setStyle(DEFAULT_STYLE);
    m_curveOutput->setStyle(DEFAULT_STYLE);
    m_curveControl->setStyle(DEFAULT_STYLE);

    m_pen1 = QPen(QColor::fromRgb(90, 90, 90));
    m_curveInput->setPen(m_pen1);
    m_curveInput->setRenderHint(QwtPlotItem::RenderAntialiased, true);

    m_pen2 = QPen(QColor::fromRgb(255, 0, 0));
    m_curveOutput->setPen(m_pen2);
    m_curveOutput->setRenderHint(QwtPlotItem::RenderAntialiased, true);

    m_pen3 = QPen(QColor::fromRgb(0, 0, 255));
    m_curveControl->setPen(m_pen3);
    m_curveControl->setRenderHint(QwtPlotItem::RenderAntialiased, true);

    m_curveInput->attach(ui->qwtInOutPlot);
    m_curveOutput->attach(ui->qwtInOutPlot);
    m_curveControl->attach(ui->qwtControlPlot);

    m_curveInput->setData(m_inputWaveform);
    m_curveOutput->setData(m_outputWaveform);
    m_curveControl->setData(m_controlWaveform);
}

void MainWindow::startSimTimer()
{
    m_stepMode = false;
    m_timer->start();
}

void MainWindow::stopSimTimer()
{
    m_stepMode = false;
    m_timer->stop();
}

void MainWindow::copyPlotToClipboard()
{
    QPixmap px = QPixmap::grabWidget(ui->centralwidget);

    QApplication::clipboard()->setPixmap(px);
}

void MainWindow::stepSimTimer(){
    //m_stepMode = true;
    //m_timer->start();

    stepSimTimer(1);
}

void MainWindow::stepSimTimer(unsigned stepSize)
{
    m_stepMode = true;
    while(stepSize--)
    {
        on_timer();
    }
    replot();
}

void MainWindow::changeSimTiming(int interval)
{
    m_timer->setInterval(interval);
}

void MainWindow::resetView()
{
    m_inputWaveform->clear();
    m_outputWaveform->clear();
    m_controlWaveform->clear();
    ui->qwtInOutPlot->replot();
    ui->qwtControlPlot->replot();
}

void MainWindow::setAntiAliasing(bool antiAliasing)
{
    m_curveInput->setRenderHint(QwtPlotItem::RenderAntialiased, antiAliasing);
    m_curveControl->setRenderHint(QwtPlotItem::RenderAntialiased, antiAliasing);
    m_curveOutput->setRenderHint(QwtPlotItem::RenderAntialiased, antiAliasing);
}

void MainWindow::changePlotStyle(QwtPlotCurve::CurveStyle style)
{
    m_curveInput->setStyle(style);
    m_curveControl->setStyle(style);
    m_curveOutput->setStyle(style);
}

void MainWindow::changePlotBufferSize(unsigned size)
{
    if(size < 3)
        return;

    m_inputWaveform->resize(size);
    m_outputWaveform->resize(size);
    m_controlWaveform->resize(size);

    ui->qwtInOutPlot->replot();
    ui->qwtControlPlot->replot();
}

void MainWindow::setPlotWidth(double width)
{
    m_pen1.setWidthF(width);
    m_pen2.setWidthF(width);
    m_pen3.setWidthF(width);

    m_curveInput->setPen(m_pen1);
    m_curveOutput->setPen(m_pen2);
    m_curveControl->setPen(m_pen3);

    replot();
}

//void MainWindow::on_pushButton_clicked()
//{
//    static int i = 1;
//    DefaultSimulationBridge dsb;

//    std::ostringstream o;
//    o << "Test nr ";
//    o << i++;
//    dsb.log(o.str());
//}

void MainWindow::on_timer()
{
    m_simulator->doStep();

    unsigned int csample = m_simulator->currentSampleNum();
    m_outputWaveform->insertSample(QPointF(csample, m_simulator->getOutputValue()));
    m_inputWaveform->insertSample(QPointF(csample, m_simulator->getInputValue()));
    m_controlWaveform->insertSample(QPointF(csample, m_simulator->getControllerOutput()));


    if(!m_stepMode)
        replot();
}

void MainWindow::replot()
{
    ui->qwtInOutPlot->setAxisScale(QwtPlot::xBottom, m_outputWaveform->getXMin(), m_outputWaveform->getXMax());
    ui->qwtInOutPlot->replot();

    ui->qwtControlPlot->setAxisScale(QwtPlot::xBottom, m_controlWaveform->getXMin(), m_controlWaveform->getXMax());
    ui->qwtControlPlot->replot();
}

void MainWindow::on_actionModel_editor_triggered()
{
    m_simSettings->show();
}

void MainWindow::on_actionSaveAs_triggered()
{
    saveSelectFile();
    saveConfiguration();
}

void MainWindow::on_actionSave_triggered()
{
    if(m_neverSaved || m_configurationFile.isNull())
        saveSelectFile();

    saveConfiguration();
}

void MainWindow::saveSelectFile()
{
    m_configurationFile = QFileDialog::getSaveFileName(this, "Save as");
    m_neverSaved = false;
}

void MainWindow::saveConfiguration()
{
    if(m_configurationFile.isNull())
        return;

    try
    {
        m_simulator->saveConfiguration(m_configurationFile.toStdString());
    }
    catch(std::logic_error& e)
    {
        QMessageBox::warning(this, "Error", e.what());
    }
}

bool MainWindow::releaseConfiguration()
{
    int res = QMessageBox::question(this, "Save changes?", "Do you want to save changes?",
                                    "Yes", "No", "Cancel");
    switch(res)
    {
    case 0:
        on_actionSave_triggered();  // Wymuś zdarzenie zapisania pliku.
    case 1:
        return true;
    default:
        return false;
    }
}

void MainWindow::on_actionOpen_triggered()
{
    releaseConfiguration();

    try
    {
        m_configurationFile = QFileDialog::getOpenFileName(this, "Open");
        m_simulator->loadConfiguration(m_configurationFile.toStdString());
    }
    catch(std::logic_error& e)
    {
        QMessageBox::warning(this, "Error", e.what());
    }

    m_simSettings->refreshAll();
}
